﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace FemtoHttpd
{
    public class FemtoHttpServer
    {   
        public Dictionary<string, Func<FemtoHttpContext, FemtoHttpResponse>> Get { get; } = new Dictionary<string, Func<FemtoHttpContext, FemtoHttpResponse>>();
        public Dictionary<string, Func<FemtoHttpContext, FemtoHttpResponse>> Post { get; } = new Dictionary<string, Func<FemtoHttpContext, FemtoHttpResponse>>();
        public Dictionary<string, Func<FemtoHttpContext, FemtoHttpResponse>> Put { get; } = new Dictionary<string, Func<FemtoHttpContext, FemtoHttpResponse>>();
        public Dictionary<string, Func<FemtoHttpContext, FemtoHttpResponse>> Delete { get; } = new Dictionary<string, Func<FemtoHttpContext, FemtoHttpResponse>>();

        private FemtoHttpListener _listener;
        public Func<FemtoHttpContext, FemtoHttpResponse> NotFound { set; get; }

        public bool Run { private set; get; }
        public void Start(int localport)
        {
            IPEndPoint localEP = new IPEndPoint(IPAddress.Any, localport);
            _listener = new FemtoHttpListener(new TcpListener(localEP));
            _listener.Start();
            Run = true;
            ThreadPool.QueueUserWorkItem(new WaitCallback((o) =>
            {
                while (true)
                {
                    try
                    {
                        var context = _listener.GetContext();
                        ListenerConnectionReceived(context);
                    }
                    catch (Exception) { }
                }
            }
            ), null);
        }
        public void Stop()
        {
            Run = false;
            _listener?.Stop();
        }
        private void ListenerConnectionReceived(FemtoHttpContext context)
        {
            bool q=ThreadPool.QueueUserWorkItem(new WaitCallback((o) =>
            {
                try
                {
                    FemtoHttpResponse response = ProcessRequest(context);
                    response?.ProcessResponse();
                }
                catch (Exception e)
                {
                    Debug.WriteLine(e.Message);
                }
                try
                {
                    context.TcpClient.Close();
                }
                catch (Exception)
                {
                }
            }), null);
            if (!q)
            {
                try
                {
                    context.TcpClient.Close();
                }
                catch (Exception)
                {
                }
            }
        }
        /// <summary>
        /// 前置处理，返回null,交由标准处理
        /// </summary>
        public Func<FemtoHttpContext, FemtoHttpResponse> PreProcessRequest { set; get; }
        /// <summary>
        /// 标准处理，返回null响应404
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        private FemtoHttpResponse NormalProcessRequest(FemtoHttpContext context)
        {
            var request = context.Request;
            Func<FemtoHttpContext, FemtoHttpResponse> processor = null;

            if (request.Method == "GET")
            {
                Get.TryGetValue(request.Url, out processor);
            }
            else if (request.Method == "POST")
            {
                Post.TryGetValue(request.Url, out processor);
            }
            else if (request.Method == "PUT")
            {
                Put.TryGetValue(request.Url, out processor);
            }
            else if (request.Method == "DELETE")
            {
                Delete.TryGetValue(request.Url, out processor);
            }

            if (processor != null)
            {
                FemtoHttpResponse response = processor.Invoke(context);
                return response;
            }
            return null;
        }

        private FemtoHttpResponse ProcessRequest(FemtoHttpContext context)
        {
            var request = context.Request;
            if (request != null)
            {
                return PreProcessRequest?.Invoke(context) ?? NormalProcessRequest(context) ??
                    NotFound?.Invoke(context)??  new SimpleResponse(context.Output) { Status = FemtoHttpStatus.NotFound, Body = "404,Not Found!……" };
            }
            return null;
        }
    }
}
